#include "StdAfx.h"
//-------------------------------------------------------------------------------------------------
//ImageProcFn.cpp  - Implementation of an Image Processing Funciton (Step)           
//-------------------------------------------------------------------------------------------------
//FreeBSD License
//Copyright 2012 Will Stott All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are
//permitted provided that the following conditions are met:
//
//   1. Redistributions of source code must retain the above copyright notice, this list of
//      conditions and the following disclaimer.
//
//   2. Redistributions in binary form must reproduce the above copyright notice, this list
//      of conditions and the following disclaimer in the documentation and/or other materials
//      provided with the distribution.
//
//THIS SOFTWARE IS PROVIDED BY Will Stott ``AS IS'' AND ANY EXPRESS OR IMPLIED
//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Will Stott OR
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//The views and conclusions contained in the software and documentation are those of the
//authors and should not be interpreted as representing official policies, either expressed
//or implied, of Will Stott.
//
//----Authors--------------------------------------------------------------------------------------
//created by: will.stott@ucl.ac.uk Feb 2012
//
//----Comments-------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------
#include "TinyXmlLib.h"
#include "TinyXmlHelper.h"
#include "ImageExptLib.h"
#include "ImageProcStepLibAuto.h"
#include "ImageProcStep.h"
#include "ImageProcFn.h"

const char * const ImageProcFn::BadName = "[badname]";
const char * const ImageProcFn::BadDescription = "[badDescription]";

ImageProcFn::ImageProcFn(void) : 
	_functionName(ImageProcFn::BadName),
	_functionDescription(ImageProcFn::BadDescription),
	_AnalysisFn(false),
	_error(true)
{
}

ImageProcFn::ImageProcFn(ImageProcFn *def) :
	_functionName((def != '\0') ? def->GetFunctionName() : ImageProcFn::BadName),
	_functionDescription((def != '\0') ? def->GetFunctionDescription() : ImageProcFn::BadDescription),
	_AnalysisFn(false),
	_error(true)
{

	if (def == '\0')
		ImageExptLib::LogMsg("ImageProcFn::ImageProcFn(ImageProcFn *def)", "ERROR: def is null");		
	else
	{
		if (def->IsValid() == false)
			ImageExptLib::LogMsg("ImageProcFn::ImageProcFn(ImageProcFn *def)", "ERROR: %s->IsValid failed", def->GetFunctionName());	
		else
		{
			_error = false;
			for (int x = 0; x < def->GetParamDefCnt(IPluginICProcStepsParamDef::input); x++ )
			{
				if (_params.AddParamDef(ProcParamDef::CreateProcParamDef(def->GetParamDef(x, IPluginICProcStepsParamDef::input))) == false)
				{
					ImageExptLib::LogMsg("ImageProcFn::ImageProcFn(ImageProcFn *def)", "ERROR: %s: input param %d copy failed", def->GetFunctionName(), x);	
					_error = true;
					break;
				}
			}

			std::string Score(IPluginICProcStepsParamAttribOutputNameScore);
			for (int x = 0; x < def->GetParamDefCnt(IPluginICProcStepsParamDef::output); x++ )
			{
				ProcParamDef *param = def->GetParamDef(x, IPluginICProcStepsParamDef::output);
				if (_params.AddParamDef(ProcParamDef::CreateProcParamDef(param)) == false)
				{
					ImageExptLib::LogMsg("ImageProcFn::ImageProcFn(ImageProcFn *def)", "ERROR: %s: output param %d copy failed", def->GetFunctionName(), x);
					_error = true;
					break;
				}
				else
				{
					if (param->GetName() == Score )
					{
						_AnalysisFn = true;
						UpdateFunctionDescriptionForAnalysis();
					}
				}
			}
			if (_error == false)
			{
				if (Validate() == false)
				{
					ImageExptLib::LogMsg("ImageProcFn::ImageProcFn(ImageProcFn *def)", "ERROR: %s: validation of copied object failed", def->GetFunctionName());
					_error = true;
				}
			}
		}
	}
}

ImageProcFn::~ImageProcFn(void)
{
}

bool   ImageProcFn::AddParamDef(ProcParamDef *param) 
{ 
	bool rc = false;

	if (param == '\0')
		ImageExptLib::LogMsg("ImageProcFn::AddParamDef()", "ERROR: %s() input param is NULL", _functionName.c_str());
	else
	{
		if (_params.AddParamDef(param) == false)
			ImageExptLib::LogMsg("ImageProcFn::AddParamDef()", "ERROR: %s()->_params.AddParamDef([%s] %s) failed", _functionName.c_str(), (param->GetDirection() == IPluginICProcStepsParamDef::input) ? "in" : "out", param->GetName());
		else
		{
			std::string Score(IPluginICProcStepsParamAttribOutputNameScore);
			if ( param->GetName() == Score )
			{
				_AnalysisFn = true;
				UpdateFunctionDescriptionForAnalysis();
			}
			_error = true; //although Validate() does all the validation done in ProcParamsDefs::AddParamDef(param), it also needs to check that the collection of params is valid - i.e. no missing indexs, result param etc
			rc = true;
		}
	}
	 return rc;
}

bool	ImageProcFn::SaveFunctionDefToXml(void *xmlStep)	//this is called from ImageProcStepLibAuto::SaveLibFunctionDefsToIef() - a friend
{
	bool rc = false;

	if (IsValid() == false)
		ImageExptLib::LogMsg("ImageProcFn::SaveFunctionDefToXml()", "ERROR: %s()->IsValid() failed", _functionName.c_str());
	else
	{
		TiXmlElement *step = static_cast<TiXmlElement *>(xmlStep);
		if (step == '\0')
			ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: step is null", GetFunctionName());	
		else
		{
			if ( IsValid() == false )
				ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: function has not been validated", GetFunctionName());	
			else
			{
				std::string xmlName(step->Value());
				if ( xmlName != ImageProcStep::xmlProcStep )
					ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s : passed <%s> should be <%s>", GetFunctionName(), xmlName, ImageProcStep::xmlProcStep);		
				else
				{
					rc = true;
							//function name
					step->SetAttribute(ImageProcStep::attribFunctionName, GetFunctionName());
					if ( _AnalysisFn == true )
						step->SetAttribute(ImageProcStep::attribStepAnalysis, ImageProcStep::attribStepAnalysisYes);
							//inputs
					int cnt = GetParamDefCnt(IPluginICProcStepsParamDef::input);
					TiXmlElement *inputs = TinyXmlLib::CreateSection (step, ProcParamsInputs::xmlInputs, GetFunctionName());
					if (inputs == '\0')
						ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: unable to create input <%s>", GetFunctionName(), ProcParamsInputs::xmlInputs);
					else
					{
						inputs->SetAttribute(ProcParams::attribParamCnt, cnt);
						int x = 0;
						for (x = 0; x < cnt; x++ )
						{
							ProcParamDef *def = GetParamDef(x, IPluginICProcStepsParamDef::input);
							if (def == '\0')
								ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: ProcParamDef for input param=%d is null", GetFunctionName(), x);
							else
							{
								TiXmlElement *xmlElementForParam = TinyXmlLib::CreateSection (inputs, IPluginICProcStepsParamXmlProcParam, def->GetDefaultValueStr());
								if (xmlElementForParam == 0)
								{
									ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: unable to create xml section for input param=%d", GetFunctionName(), x);
									break;
								}
								else
								{
									if (def->SetXml(xmlElementForParam) == false)
									{
										ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: unable to set xml attributes for input param=%d", GetFunctionName(), x);
										break;
									}
								}
							}
						}
						if (cnt != x)
						{
							ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: unable to create input <%s> %d", GetFunctionName(), IPluginICProcStepsParamXmlProcParam, x);
							rc = false;
						}
					}
							//outputs
					cnt = GetParamDefCnt(IPluginICProcStepsParamDef::output);
					TiXmlElement *outputs = TinyXmlLib::CreateSection (step, ProcParamsOutputs::xmlOutputs, GetFunctionName());
					if (outputs == '\0')
						ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: unable to create output <%s>", GetFunctionName(), ProcParamsOutputs::xmlOutputs);
					else
					{
						outputs->SetAttribute(ProcParams::attribParamCnt, cnt);
						int x = 0;
						for (x = 0; x < cnt; x++ )
						{
							ProcParamDef *def = GetParamDef(x, IPluginICProcStepsParamDef::output);
							if (def == '\0')
								ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: ProcParamDef for output param=%d is null", GetFunctionName(), x);
							else
							{
								TiXmlElement *xmlElementForParam = TinyXmlLib::CreateSection (outputs, IPluginICProcStepsParamXmlProcParam, def->GetDefaultValueStr());
								if (xmlElementForParam == 0)
								{
									ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: unable to create xml section for output param=%d", GetFunctionName(), x);
									break;
								}
								else
								{
									if (def->SetXml(xmlElementForParam) == false)
									{
										ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: unable to set xml attributes for output param=%d", GetFunctionName(), x);
										break;
									}
								}
							}
						}
						if (cnt != x)
						{
							ImageExptLib::LogMsg("ImageProcStepLibAuto::SaveFunctionDefToXml()", "ERROR: %s: unable to create output <%s> %d", GetFunctionName(), IPluginICProcStepsParamXmlProcParam, x);
							rc = false;
						}
					}
				}
			}
		}
	}
	return rc;
}

bool ImageProcFn::SetFunctionName(const char *Name)
{ 
	bool rc = false;

	if (Name == '\0')
		ImageExptLib::LogMsg("ImageProcFn::SetFunctionName()", "ERROR: input param is NULL");
	else
	{
		_functionName = Name;
		_error = true;						//now call Validate() - GetApi() returns '\0' until ImageProcFn object is valid
		rc = true;
	}
	return rc;
}

bool ImageProcFn::SetFunctionDescription(const char *Text)
{ 
	bool rc = false;

	if (Text == '\0')
		ImageExptLib::LogMsg("ImageProcFn::SetFunctionDescription()", "ERROR: %s() input param is NULL", _functionName.c_str());
	else
	{
		std::string temp(Text);
		if (temp[0] == '(')
			temp[0] = '[';
		_functionDescription = temp;
		if (IsAnalysisFn())
			UpdateFunctionDescriptionForAnalysis();
		_error = true;						//now call Validate() - GetApi() returns '\0' until ImageProcFn object is valid
		rc = true;
	}
	return rc;
}

void ImageProcFn::UpdateFunctionDescriptionForAnalysis()
{
	if ((_functionDescription[0] != '(') && (IsAnalysisFn()))
	{
		std::string temp(_functionDescription);
		_functionDescription = "(analysis) ";
		_functionDescription += temp;
	}
}

int	ImageProcFn::GetParamDefCnt(IPluginICProcStepsParamDef::Direction dir)
{
	int rc = ImageProcFn::Invalid;

	if (IsValid() == false)
		ImageExptLib::LogMsg("ImageProcFn::GetParamDefCnt()", "ERROR: %s()->IsValid() failed", _functionName.c_str());
	else
	{
		rc = 0;
		int cnt = _params.GetParamDefCount();
		for (int pos = 0; pos < cnt; pos++ ) 
		{
			ProcParamDef *param = _params.GetParamDefByPosition(pos);
			if (param != '\0')
			{
				if (param->GetDirection() == dir)
					rc++;
			}
		}
	}
	return rc;
}


ProcParamDef * ImageProcFn::GetParamDef(int index, IPluginICProcStepsParamDef::Direction dir)
{
	ProcParamDef *rc = '\0';

	if (IsValid() == false)
		ImageExptLib::LogMsg("ImageProcFn::GetParamDef()", "ERROR: %s()->IsValid() failed", _functionName.c_str());
	else
	{
		int cnt = _params.GetParamDefCount();
		for (int pos = 0; pos < cnt; pos++ ) 
		{
			ProcParamDef *param = _params.GetParamDefByPosition(pos);
			if (param != '\0')
			{
				if ((param->GetDirection() == dir) && (param->GetIndex() == index))
				{
					rc = param;
					break;
				}
			}
		}
		if ( rc == '\0')
			ImageExptLib::LogMsg("ImageProcFn::GetParamDef()", "ERROR: %s() %s Param index %d not found", _functionName.c_str(), (dir == IPluginICProcStepsParamDef::input) ? "input" : "output", index);
	}
	return rc;
}


bool ImageProcFn::Validate()
{
	if ( _functionName.length() <= 0 )
		_error = true, ImageExptLib::LogMsg("ImageProcFn::Validate()", "ERROR: function name not set");
	else
	{
		if ( _functionDescription.length() <= 0 )
			_error = true, ImageExptLib::LogMsg("ImageProcFn::Validate()", "ERROR: %s() description not set", _functionName.c_str());
		else
		{
			if (_params.Validate() != true )
				_error = true, ImageExptLib::LogMsg("ImageProcFn::Validate()", "ERROR: %s()->_params.Validate() failed", _functionName.c_str());
			else
			{
				if ( _AnalysisFn == false )
					_error = false;
				else
				{
					if (_params.GetParamDef(IPluginICProcStepsParamAttribOutputNameScore) == '\0')
						_error = true, ImageExptLib::LogMsg("ImageProcFn::Validate()", "ERROR: %s()is Analysis Function, but output param name %s not found", _functionName.c_str(), IPluginICProcStepsParamAttribOutputNameScore);
					else
						_error = false;
				}
			}
		}
	}
	return (_error == false) ? true : false;
}

bool ImageProcFn::IsMatch(const char *FunctionName, ProcParamsOutputs *outputs, ProcParamsInputs *inputs)
{
	bool rc = false;

	if (IsValid() == false)
		ImageExptLib::LogMsg("ImageProcFn::IsMatch()", "ERROR: %s->IsValid()->failed", _functionName.c_str());	
	else
	{
		if ( _functionName != FunctionName )
			ImageExptLib::LogMsg("ImageProcFn::IsMatch()", "ERROR: %s not same as passed name %s", _functionName.c_str(), FunctionName);	
		else
		{
			if (_params.IsMatch(outputs, inputs) == false)	//do all input and output parameters match by name, type, range,
				ImageExptLib::LogMsg("ImageProcFn::IsMatch()", "ERROR: %s failed to match i/o params", _functionName.c_str());
			else
				rc = true;
		}
	}
	return rc;
}


//-------------------------------------------------------------------------------------------------
//			E N D   O F   F I L E
//-------------------------------------------------------------------------------------------------


